#include <string>
#include <algorithm>
#include <functional>
#include <iostream>
#include <fstream>
#include "XMLStrParser.h"
#define NEWS_BENCHMARK 1
#include "NewsBenchMark.h"
// trim from start 


int testXMLStrParser()
{
    std::ifstream in( "d:\\temp\\0.xml");
    char* buf = new char[4096000];
    memset(buf, 0, 4096000);
    in.read( buf, 4096000);

    std::string dateid;
    std::string newsId;
    std::string revisionid;
    std::string prevRevId;
    std::string publicId;
    std::string firstC;
    std::string thisC;
    std::string language;
    std::string author;
    std::string headline;
    std::string slugline;
    std::vector<std::string> bwcodes;
    std::vector<std::string> contries;
    std::vector<std::string> regions;

    TIMESTART("OverHead");
    TIMESTOP("OverHead");

    //Try index all

    TIMESTART("Index");
    //XMLNode(buf).Sibling("lkefjlefkjelekjf");
    TIMESTOP("Index");

    TIMESTART("ONE Hit");
   // XMLNode(buf).Sibling("html");
    TIMESTOP("ONE Hit");
    TIMESTART("t");



    char* NewsItem = XMLNode( buf ).Next("NewsItem", XMLNode::sibling).Pointer();
    char* NewsIdentifier = XMLNode( NewsItem).Next("NewsIdentifier", XMLNode::sibling).Pointer();


    XMLNode( NewsIdentifier ).Child("NewsItemId").Content(newsId);
    XMLNode( NewsIdentifier ).Child("RevisionId").Content(revisionid).Attr("PreviousRevision", prevRevId);
    XMLNode( NewsIdentifier).Child("PublicIdentifier").Content(publicId);

    char* NewsManagement = XMLNode(NewsItem).Child("NewsManagement").Pointer();

    XMLNode(NewsManagement).Child("FirstCreated").Content(firstC);
    XMLNode(NewsManagement).Child("ThisRevisionCreated").Content(thisC);

    char* NewsComponent = XMLNode(NewsItem).Decsendant("NewsComponent").Pointer();

    XMLNode(NewsComponent).Sibling("Language").Attr("FormalName", language);

    char* Metadata = XMLNode(NewsComponent).Decsendant("Metadata").Pointer();

    XMLNode prop( XMLNode(Metadata).Sibling("Property").Pointer());

    std::string formalName;
    std::string propval;

    while( prop )
    {
        prop.Attr("FormalName", formalName ).Attr("Value", propval);
        if( formalName == "BWIndustryKeywords")
        {
            bwcodes.push_back(propval);
        }else if( formalName == "BWCountryKeywords")
        {
            contries.push_back( propval );
        }else if( formalName == "BWRegionKeywords")
        {
            regions.push_back( propval );
        }
        prop.Next("Property");
    }

    char* NewsLines = XMLNode(NewsComponent).Decsendant("NewsLines").Pointer();
    XMLNode(NewsLines).Sibling("HeadLine").Content(headline);
    XMLNode(NewsLines).Sibling("SlugLine").Content(slugline);
    std::string newsline_content;
    
    while( NewsLines )
    {
        XMLNode(NewsLines).Child("ByLine").Content( author );
        char* NewsLine = XMLNode( NewsLines ).Child("NewsLine").Child("NewsLineType").Attr("FormalName", newsline_content).Pointer();
        if( newsline_content.length() > 0 && newsline_content.find("FSA ") != std::string::npos )
        {
            break;
        }
        NewsLines = XMLNode(NewsLines).SiblingUnderParent("NewsLines",NewsComponent ).Pointer();
    }

    char* NewsComponentBody = XMLNode(NewsComponent).Child("NewsComponent").Pointer();
    bool body = false;
    std::string role;
    while( !body )
    {
        XMLNode(NewsComponentBody).Child("Role").Attr("FormalName", role);
        if( role == "Body" || role == "CompositeBody" )
            body = true;
        else
            NewsComponentBody = XMLNode(NewsComponentBody).Sibling("NewsComponent").Pointer();
    }

    //Now we get the body component
    char* bodyXhtml = XMLNode(NewsComponentBody).Sibling("html").Pointer();

    TIMESTOP("t");

    std::cout<<"dateid"<<dateid<<std::endl;
    std::cout<<"newsId"<<newsId<<std::endl;
    std::cout<<"revisionid"<<revisionid<<std::endl;
    std::cout<<"PreviousRevision"<<prevRevId<<std::endl;
    std::cout<<"publicId"<<publicId<<std::endl;
    std::cout<<"firstC"<<firstC<<std::endl;
    std::cout<<"thisC"<<thisC<<std::endl;
    std::cout<<"language"<<language<<std::endl;
    std::cout<<"headline"<<headline<<std::endl;
    std::cout<<"slugline"<<slugline<<std::endl;
    std::cout <<"author" << author << std::endl;

    for( std::vector<std::string>::iterator it = contries.begin(); it != contries.end(); ++it)
    {
        std::cout << "Country: " << *it << std::endl;
    }

    for( std::vector<std::string>::iterator it = regions.begin(); it != regions.end(); ++it)
    {
        std::cout << "Region: " << *it << std::endl;
    }

    for( std::vector<std::string>::iterator it = bwcodes.begin(); it != bwcodes.end(); ++it)
    {
        std::cout << "BWCode: " << *it << std::endl;
    }

    delete[] buf;
    return 0;
}

void testXMLNodeCache()
{

    XMLNodeCache cache;
    XMLNodeCache::record_type val((char*)1345, 1);
    std::vector<XMLNodeCache::record_type> vals;

    cache.PushBack(val);
    vals.push_back( val);
    val = XMLNodeCache::record_type((char*)1346, 2);
    cache.PushBack(val);
    vals.push_back( val);

    for( int i = 10400; i < 12400; i ++ )
    {
        val = XMLNodeCache::record_type((char*)i, 3 );
        cache.PushBack( val );
        vals.push_back( val);
    }
    val.point = (char*)1346;
    XMLNodeCache::iterator it;
    if( ! cache.LocateRecord(val, it) == XMLNodeCache::err_ok )
    {
        std::cout << "Failed at testXMLNodeCache" << std::endl;
    }
    {
        TIMECLICK("Cache Lookup10", cache_lookup );
        for( std::vector<XMLNodeCache::record_type>::iterator it2 = vals.begin(); it2 != vals.end(); ++it2 )
        {
            if( cache.LocateRecord( *it2, it ) != XMLNodeCache::err_ok )
                std::cout << "Failed 2" << std::endl;
            if( it2->point != it->point )
                std::cout << "Failed 3" << std::endl;
        }
    }

    char* p;
    int l;
    if( cache.GetHint( (char*) 10401, 3, 2, 4, 0, 0, p, l ) != XMLNodeCache::err_ok)
    {
        std::cout << "Failed 4" <<std::endl;
    }

    cache.Init();
    {
        for( std::vector<XMLNodeCache::record_type>::iterator it2 = vals.begin(); it2 != vals.end(); ++it2 )
        {
            if( cache.LocateRecord( *it2, it ) == XMLNodeCache::err_ok )
                std::cout << "Failed 2" << std::endl;
        }
    }

    val = XMLNodeCache::record_type((char*)1, 0);
    cache.PushBack( val );
    val =  XMLNodeCache::record_type((char*)2, 1);
    cache.PushBack( val ); 
    val = XMLNodeCache::record_type((char*)3, 2);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)4, 3);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)5, 4);
    cache.PushBack( val );   
    val = XMLNodeCache::record_type((char*)6, 4);
    cache.PushBack( val );  
    val = XMLNodeCache::record_type((char*)7, 3);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)8, 4);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)9, 4);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)10, 5);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)11, 2);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)12, 2);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)13, 3);
    cache.PushBack( val );
    val = XMLNodeCache::record_type((char*)14, 4);
    cache.PushBack( val );


    {
        char* p;
        int level;
        //Decsendant
        if( cache.GetHint((char*)1, 0, 4, 7, 0, 0, p, level) != XMLNodeCache::err_ok )
            std::cout << "Fail at 13" << std::endl;
        if( (int)p != 5 || level != 4 )
            std::cout << "fail at 14" << std::endl;

        //Next
        if( cache.GetHint((char*) 5, 4, 4, 4, 0, 3, p, level) != XMLNodeCache::err_ok )
            std::cout << "Failed at 13" << std::endl;
        if( (int)p != 6 || level != 4 )
            std::cout << "Failed at 14" << std::endl;
        //parent
        if( cache.GetHint((char*) 5, 4, 3, 3, 0, 0, p, level, false) != XMLNodeCache::err_ok )
            std::cout << "Failed at 13" << std::endl;
        if( (int)p != 4 || level != 3 )
            std::cout << "Failed at 14" << std::endl;
        //Fail Next
        if( cache.GetHint((char*) 9, 4, 4, 4, 0, 3, p, level) == XMLNodeCache::err_ok )
            std::cout << "Failed at 13" << std::endl;
        //Sibling
        if( cache.GetHint((char*) 5, 4, -1, -1, 0, 0, p, level) != XMLNodeCache::err_ok )
            std::cout << "Failed at 13" << std::endl;
        if( (int)p != 6 || level != 4 )
            std::cout << "Failed at 14" << std::endl;
        //Next or Descan
        if( cache.GetHint((char*) 3, 2, 3, 4, 0, 2, p, level) != XMLNodeCache::err_ok )
            std::cout << "Failed at 13" << std::endl;
        if( (int)p != 4 || level != 3 )
            std::cout << "Failed at 14" << std::endl;

    }

}


int main()
{
    testXMLNodeCache();
    testXMLStrParser();
    NewsBenchmark::Instance()->Log( std::cout);
    return 0;
}
